package com.itchen.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itchen.convert.UploadConvert;
import com.itchen.emtity.dataobject.UploadDO;
import com.itchen.emtity.vo.UploadVO;
import com.itchen.exception.BusinessException;
import com.itchen.exception.code.BaseResponseCode;
import com.itchen.repository.FileUploadRepository;
import com.itchen.service.FileUploadService;
import com.itchen.util.PathUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
public class FileUploadServiceImpl implements FileUploadService {

    @Autowired
    private FileUploadRepository fileUploadRepository;

    @Autowired
    private UploadConvert uploadConvert;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uploadFile(MultipartFile file) throws IOException {
        //上传文件
        UploadDO upload = upload(file);

        //将上传文件的相关数据保存到数据库
        int row = fileUploadRepository.createUploadData(upload);
    }

    @Override
    public PageInfo<UploadDO> getUploadFileList(Integer page, Integer limit, String orName) {
        //进行物理分页
        PageHelper.startPage(page, limit);
        List<UploadDO> uploadDOList = fileUploadRepository.getUploadFileList(orName);
        PageInfo<UploadDO> pageInfo = new PageInfo<>(uploadDOList);
        pageInfo.setTotal(fileUploadRepository.getCount());
        return pageInfo;
    }

    /**
     * 根据id删除上传文件数据
     * @param uploadId
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteUploadFileDataById(String uploadId) {
        UploadDO uploadDO = fileUploadRepository.getUploadFileById(uploadId);
        fileUploadRepository.deleteUploadFileDataById(uploadId);
        File file = new File(uploadDO.getFilePath());
        file.delete();
    }

    /**
     * 下载文件流程
     * @param response
     */
    @Override
    public void downloadUploadFilesData(String uploadId, String sign, HttpServletResponse response){
        //根据id获取文件数据
        UploadDO uploadDO = fileUploadRepository.getUploadFileById(uploadId);
        //检测需要下载的文件是否存在
        checkFileExist(uploadDO);
        //下载文件
        downloadFile(uploadDO,sign,response);

    }

    /**
     * 检验下载的文件是否存在
     */
    private void checkFileExist(UploadDO uploadDO) {
        File file = new File(uploadDO.getFilePath());
        if (!file.exists()){
            fileUploadRepository.deleteUploadFileDataById(uploadDO.getUploadId());
            throw new BusinessException(BaseResponseCode.FILE_ERROR);
        }
    }

    /**
     * 文件下载
     * @param uploadDO
     * @param response
     * @throws IOException
     */
    @Transactional(rollbackFor = Exception.class)
    public void downloadFile(UploadDO uploadDO, String sign, HttpServletResponse response){

        try {
            if (sign == null){
                //下载数量加一
                fileUploadRepository.downloadNumberAddOne(uploadDO);
            }
            sign = (sign == null ? "attachment" : "inline");
            //获取文件输入流
            InputStream is = new FileInputStream(new File(uploadDO.getFilePath()));
            //附件下载
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            response.setHeader("Content-Disposition", sign+";filename="+ URLEncoder.encode(uploadDO.getOriginalName(),"UTF-8"));
            //获取响应输出流
            OutputStream os = response.getOutputStream();
            //文件拷贝
            IOUtils.copy(is,os);
            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(os);
        }catch (IOException e){
            throw new BusinessException(BaseResponseCode.DOWNLOAD_ERROR);
        }
    }

    @Override
    public UploadVO getUploadFileById(String uploadId) {
        UploadDO uploadDO = fileUploadRepository.getUploadFileById(uploadId);
        return uploadConvert.uploadDOToVO(uploadDO);
    }

    @Override
    public void deleteUploadFileDataByIds(List<UploadVO> uploadVOS) {
        List<UploadDO> uploadDOS = uploadVOS.parallelStream().map(uploadConvert::uploadVOToDO).collect(Collectors.toList());
        fileUploadRepository.deleteUploadFileDataByIds(uploadDOS);
        uploadDOS.forEach(upload->{
            File file = new File(upload.getFilePath());
            file.delete();
        });
    }

    /**
     * 上传文件
     * @param file
     * @return
     * @throws IOException
     */
    private UploadDO upload(MultipartFile file) throws IOException {
        String dir = getDir(file);
        String newName = UUID.randomUUID().toString().replaceAll("-", "");
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        file.transferTo(new File(dir+newName+suffix));
        UploadDO uploadDO = createFileData(file,newName,suffix,dir);
        return uploadDO;
    }

    /**
     * 封装文件数据
     * @param file
     * @return
     */
    private UploadDO createFileData(MultipartFile file,String newName,String suffix,String dir) {
        UploadDO uploadDO = new UploadDO();
        uploadDO.setUploadId(newName).
                setFileSize(file.getSize()).
                setFileType(file.getContentType()).
                setOriginalName(file.getOriginalFilename()).
                setCreateTime(new Date()).
                setNewName(newName+suffix).
                setFilePath(dir+newName+suffix);
        return uploadDO;
    }

    /**
     *创建目录
     * @return
     */
    public String getDir(MultipartFile file) {
        checkFile(file);
        String filePath = PathUtils.UPLOAD_PATH.getPath();
        String dir = filePath + new SimpleDateFormat("yyyy-MM-dd").format(new Date()).replaceAll("-","");
        File exist = new File(dir);
        if (!exist.exists()) {
            exist.mkdirs();
        }
        return dir+"\\";
    }

    /**
     * 检验文件
     * @param file
     */
    private void checkFile(MultipartFile file) {
        if (file.isEmpty()) {
            throw new BusinessException(BaseResponseCode.FILE_NULL);
        }
    }
}
